/**
 * Copyright (c) 2022 KCloud-Platform-Alibaba Authors. All Rights Reserved.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 *   http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.laokou.common.core.utils;
import lombok.extern.slf4j.Slf4j;
/**
 * @author laokou
 */
@Slf4j
public class IdGenerator {

    private volatile static Snowflake instance;

    /**
     * 数据标识
     */
    private static final long DATA_ID = 1L;
    /**
     * 系统标识
     */
    private static final long SYS_ID = 1L;

    static {
        instance = new Snowflake(DATA_ID,SYS_ID);
    }

    /**
     * 默认雪花ID
     */
    public static long defaultSnowflakeId() {
        return instance.nextId();
    }

    static class Snowflake {
        /**
         * 起始的时间戳
         */
        private final static long START_TIMESTAMP = 1480166465631L;

        /**
         * 每一部分占用的位数
         * 序列号占用的位数
         */
        private final static long SEQUENCE_BIT = 13;
        /**
         * 机器标识占用的位数
         */
        private final static long MACHINE_BIT = 5;
        /**
         * 数据中心占用的位数
         */
        private final static long DATA_CENTER_BIT = 5;

        /**
         * 每一部分的最大值
         */
        private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);
        private final static long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);
        private final static long MAX_DATA_CENTER_NUM = ~(-1L << DATA_CENTER_BIT);

        /**
         * 每一部分向左的位移
         */
        private final static long MACHINE_LEFT = SEQUENCE_BIT;
        private final static long DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
        private final static long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;

        /**
         * 数据中心ID
         */
        private final long DATACENTER_ID;
        /**
         * 机器标志ID
         */
        private final long MACHINE_ID;
        /**
         * 序列号
         */
        private long sequence = 0L;
        /**
         * 上一次时间戳
         */
        private long lastTimeStamp = -1L;

        private long getNextMill() {
            long mill = getNewTimeStamp();
            while (mill <= lastTimeStamp) {
                mill = getNewTimeStamp();
            }
            return mill;
        }

        private long getNewTimeStamp() {
            return System.currentTimeMillis();
        }

        /**
         * 根据指定的数据中心ID和机器标志ID生成指定的序列号
         *
         * @param dataCenterId 数据中心ID
         * @param machineId    机器标志ID
         */
        public Snowflake(final long dataCenterId,final long machineId) {
            if (dataCenterId > MAX_DATA_CENTER_NUM || dataCenterId < 0) {
                throw new RuntimeException("DtaCenterId can't be greater than MAX_DATA_CENTER_NUM or less than 0！");
            }
            if (machineId > MAX_MACHINE_NUM || machineId < 0) {
                throw new RuntimeException("MachineId can't be greater than MAX_MACHINE_NUM or less than 0！");
            }
            this.DATACENTER_ID = dataCenterId;
            this.MACHINE_ID = machineId;
        }

        /**
         * 产生下一个ID
         *
         * @return
         */
        public synchronized long nextId() {
            long currTimeStamp = getNewTimeStamp();
            if (currTimeStamp < lastTimeStamp) {
                throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
            }

            if (currTimeStamp == lastTimeStamp) {
                //相同毫秒内，序列号自增
                sequence = (sequence + 1) & MAX_SEQUENCE;
                //同一毫秒的序列数已经达到最大
                if (sequence == 0L) {
                    currTimeStamp = getNextMill();
                }
            } else {
                //不同毫秒内，序列号置为0
                sequence = 0L;
            }

            lastTimeStamp = currTimeStamp;
            //时间戳部分
            return (currTimeStamp - START_TIMESTAMP) << TIMESTAMP_LEFT
                    //数据中心部分
                    | DATACENTER_ID << DATA_CENTER_LEFT
                    //机器标识部分
                    | MACHINE_ID << MACHINE_LEFT
                    //序列号部分
                    | sequence;
        }
    }

    public static void main(String[] args) {
        long snowflakeId = IdGenerator.defaultSnowflakeId();
        log.info("雪花id：{}",snowflakeId);
    }

}